<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Dockerfile生成器</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }

        :root {
            --primary: #2496ed;
            --primary-dark: #1a7bc9;
            --secondary: #2d3748;
            --light: #f8f9fa;
            --dark: #212529;
            --success: #28a745;
            --danger: #dc3545;
            --warning: #ffc107;
            --gray: #6c757d;
            --light-gray: #e9ecef;
        }

        body {
            background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
            color: var(--dark);
            min-height: 100vh;
            padding: 20px;
        }

        .container {
            max-width: 1400px;
            margin: 0 auto;
        }

        header {
            text-align: center;
            margin-bottom: 30px;
            padding: 20px;
            background: white;
            border-radius: 12px;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
        }

        h1 {
            font-size: 2.5rem;
            margin-bottom: 10px;
            color: var(--primary);
        }

        .subtitle {
            font-size: 1.2rem;
            color: var(--gray);
            max-width: 700px;
            margin: 0 auto;
        }

        .dashboard {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 25px;
        }

        @media (max-width: 1024px) {
            .dashboard {
                grid-template-columns: 1fr;
            }
        }

        .panel {
            background: white;
            border-radius: 12px;
            padding: 25px;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
            height: fit-content;
        }

        .panel-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 20px;
            padding-bottom: 15px;
            border-bottom: 1px solid var(--light-gray);
        }

        .panel-title {
            font-size: 1.5rem;
            color: var(--secondary);
            display: flex;
            align-items: center;
            gap: 10px;
        }

        .panel-title i {
            color: var(--primary);
        }

        .btn {
            background: var(--primary);
            color: white;
            border: none;
            padding: 10px 18px;
            border-radius: 6px;
            cursor: pointer;
            font-size: 0.95rem;
            font-weight: 500;
            transition: all 0.3s;
            display: flex;
            align-items: center;
            gap: 8px;
        }

        .btn:hover {
            background: var(--primary-dark);
            transform: translateY(-2px);
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
        }

        .btn-success {
            background: var(--success);
        }

        .btn-success:hover {
            background: #218838;
        }

        .btn-danger {
            background: var(--danger);
        }

        .btn-danger:hover {
            background: #c82333;
        }

        .btn-outline {
            background: transparent;
            color: var(--primary);
            border: 1px solid var(--primary);
        }

        .btn-outline:hover {
            background: var(--primary);
            color: white;
        }

        .config-list {
            display: flex;
            flex-direction: column;
            gap: 15px;
            margin-bottom: 20px;
        }

        .config-item {
            background: var(--light);
            border-radius: 8px;
            padding: 15px;
            border-left: 4px solid var(--primary);
            transition: all 0.3s;
        }

        .config-item:hover {
            transform: translateY(-2px);
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
        }

        .config-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 12px;
        }

        .config-type {
            font-weight: 600;
            color: var(--primary);
            font-size: 1.1rem;
        }

        .config-actions {
            display: flex;
            gap: 8px;
        }

        .config-content {
            margin-top: 10px;
        }

        .form-group {
            margin-bottom: 15px;
        }

        .form-group label {
            display: block;
            margin-bottom: 6px;
            font-weight: 500;
            color: var(--secondary);
        }

        .form-control {
            width: 100%;
            padding: 10px 12px;
            border-radius: 6px;
            border: 1px solid #ced4da;
            font-size: 1rem;
            transition: border 0.3s;
        }

        .form-control:focus {
            outline: none;
            border-color: var(--primary);
            box-shadow: 0 0 0 3px rgba(36, 150, 237, 0.2);
        }

        textarea.form-control {
            min-height: 100px;
            resize: vertical;
        }

        .preview-container {
            background: #1e1e1e;
            border-radius: 8px;
            padding: 20px;
            margin-top: 20px;
            overflow: auto;
            max-height: 500px;
        }

        .preview-header {
            color: white;
            margin-bottom: 15px;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .preview-content {
            color: #d4d4d4;
            font-family: 'Courier New', monospace;
            font-size: 0.95rem;
            line-height: 1.5;
            white-space: pre-wrap;
        }

        .keyword {
            color: #569cd6;
        }

        .comment {
            color: #6a9955;
        }

        .string {
            color: #ce9178;
        }

        .action-buttons {
            display: flex;
            gap: 12px;
            margin-top: 20px;
            flex-wrap: wrap;
        }

        .empty-state {
            text-align: center;
            padding: 40px 20px;
            color: var(--gray);
        }

        .empty-state i {
            font-size: 3rem;
            margin-bottom: 15px;
            color: var(--light-gray);
        }

        .empty-state p {
            font-size: 1.1rem;
        }

        .file-upload {
            display: none;
        }

        .upload-label {
            display: inline-block;
            cursor: pointer;
        }

        .drag-drop-area {
            border: 2px dashed #ced4da;
            border-radius: 8px;
            padding: 30px;
            text-align: center;
            margin-top: 20px;
            transition: all 0.3s;
            cursor: pointer;
        }

        .drag-drop-area:hover {
            border-color: var(--primary);
            background-color: rgba(36, 150, 237, 0.05);
        }

        .drag-drop-area i {
            font-size: 2.5rem;
            color: var(--primary);
            margin-bottom: 15px;
        }

        .drag-drop-area p {
            color: var(--gray);
            margin-bottom: 10px;
        }

        .drag-drop-area .btn {
            margin-top: 10px;
        }

        .instructions {
            background: #fff9e6;
            border-left: 4px solid var(--warning);
            padding: 15px;
            border-radius: 6px;
            margin-top: 20px;
        }

        .instructions h3 {
            color: var(--secondary);
            margin-bottom: 10px;
            display: flex;
            align-items: center;
            gap: 8px;
        }

        .instructions ul {
            padding-left: 20px;
            color: var(--gray);
        }

        .instructions li {
            margin-bottom: 8px;
        }

        .toast {
            position: fixed;
            bottom: 20px;
            right: 20px;
            background: var(--success);
            color: white;
            padding: 12px 20px;
            border-radius: 6px;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
            display: flex;
            align-items: center;
            gap: 10px;
            transform: translateY(100px);
            opacity: 0;
            transition: all 0.3s;
            z-index: 1000;
        }

        .toast.show {
            transform: translateY(0);
            opacity: 1;
        }

        .toast.error {
            background: var(--danger);
        }
    </style>
</head>
<body>
    <div class="container">
        <header>
            <h1>Dockerfile 生成器</h1>
            <p class="subtitle">轻松创建和自定义Dockerfile配置，支持实时预览和文件上传下载功能</p>
        </header>

        <div class="dashboard">
            <div class="panel">
                <div class="panel-header">
                    <h2 class="panel-title"><i class="fas fa-sliders-h"></i> 配置项</h2>
                    <button class="btn" id="addConfigBtn">
                        <i class="fas fa-plus"></i> 添加配置
                    </button>
                </div>

                <div class="config-list" id="configList">
                    <!-- 配置项将动态添加到这里 -->
                </div>

                <div class="instructions">
                    <h3><i class="fas fa-info-circle"></i> 使用说明</h3>
                    <ul>
                        <li>点击"添加配置"按钮添加新的Dockerfile指令</li>
                        <li>每个配置项都可以独立编辑和删除</li>
                        <li>右侧预览区域会实时显示生成的Dockerfile内容</li>
                        <li>支持上传现有的Dockerfile进行编辑</li>
                        <li>完成后可以下载生成的Dockerfile文件</li>
                    </ul>
                </div>
            </div>

            <div class="panel">
                <div class="panel-header">
                    <h2 class="panel-title"><i class="fas fa-eye"></i> 实时预览</h2>
                    <div class="action-buttons">
                        <button class="btn btn-outline" id="downloadBtn">
                            <i class="fas fa-download"></i> 下载
                        </button>
                        <label class="btn btn-outline upload-label">
                            <i class="fas fa-upload"></i> 上传
                            <input type="file" class="file-upload" id="fileUpload" accept=".dockerfile,.Dockerfile,.txt">
                        </label>
                        <button class="btn btn-outline" id="downloadBtn">
                            <i class="fas fa-download"></i> 构建
                        </button>
                    </div>
                </div>

                <div class="preview-container">
                    <div class="preview-header">
                        <span>Dockerfile</span>
                        <span id="lineCount">0 行</span>
                    </div>
                    <div class="preview-content" id="previewContent">
                        <span class="comment"># 生成的Dockerfile将显示在这里</span>
                        <span class="comment"># 请添加配置项开始生成</span>
                    </div>
                </div>

                <div class="drag-drop-area" id="dragDropArea">
                    <i class="fas fa-cloud-upload-alt"></i>
                    <p>拖放Dockerfile文件到这里</p>
                    <p>或</p>
                    <label class="btn upload-label">
                        <i class="fas fa-file-import"></i> 选择文件
                        <input type="file" class="file-upload" id="dragDropUpload" accept=".dockerfile,.Dockerfile,.txt">
                    </label>
                </div>

                <div class="action-buttons">
                    <button class="btn btn-success" id="copyBtn">
                        <i class="fas fa-copy"></i> 复制到剪贴板
                    </button>
                    <button class="btn btn-danger" id="resetBtn">
                        <i class="fas fa-trash-alt"></i> 重置所有配置
                    </button>
                </div>
            </div>
        </div>
    </div>

    <div class="toast" id="toast"></div>

    <script>
        // 配置项数据
        let configs = [];

        // DOM 元素
        const configList = document.getElementById('configList');
        const previewContent = document.getElementById('previewContent');
        const lineCount = document.getElementById('lineCount');
        const addConfigBtn = document.getElementById('addConfigBtn');
        const downloadBtn = document.getElementById('downloadBtn');
        const copyBtn = document.getElementById('copyBtn');
        const resetBtn = document.getElementById('resetBtn');
        const fileUpload = document.getElementById('fileUpload');
        const dragDropUpload = document.getElementById('dragDropUpload');
        const dragDropArea = document.getElementById('dragDropArea');
        const toast = document.getElementById('toast');

        // 配置类型选项
        const configTypes = [
            { value: 'FROM', label: 'FROM - 基础镜像', placeholder: '例如: ubuntu:20.04' },
            { value: 'RUN', label: 'RUN - 执行命令', placeholder: '例如: apt-get update && apt-get install -y curl' },
            { value: 'COPY', label: 'COPY - 复制文件', placeholder: '例如: . /app' },
            { value: 'ADD', label: 'ADD - 添加文件', placeholder: '例如: . /app' },
            { value: 'WORKDIR', label: 'WORKDIR - 工作目录', placeholder: '例如: /app' },
            { value: 'EXPOSE', label: 'EXPOSE - 暴露端口', placeholder: '例如: 8080' },
            { value: 'ENV', label: 'ENV - 环境变量', placeholder: '例如: NODE_ENV=production' },
            { value: 'ARG', label: 'ARG - 构建参数', placeholder: '例如: VERSION=1.0' },
            { value: 'LABEL', label: 'LABEL - 元数据', placeholder: '例如: maintainer="your@email.com"' },
            { value: 'VOLUME', label: 'VOLUME - 挂载点', placeholder: '例如: /data' },
            { value: 'USER', label: 'USER - 用户', placeholder: '例如: node' },
            { value: 'CMD', label: 'CMD - 默认命令', placeholder: '例如: ["npm", "start"]' },
            { value: 'ENTRYPOINT', label: 'ENTRYPOINT - 入口点', placeholder: '例如: ["nginx", "-g", "daemon off;"]' },
            { value: 'HEALTHCHECK', label: 'HEALTHCHECK - 健康检查', placeholder: '例如: CMD curl -f http://localhost/ || exit 1' }
        ];

        // 初始化
        function init() {
            // 添加示例配置
            addConfig('FROM', 'ubuntu:20.04');
            addConfig('RUN', 'apt-get update && apt-get install -y curl');
            addConfig('WORKDIR', '/app');
            addConfig('COPY', '. /app');
            addConfig('EXPOSE', '8080');
            addConfig('CMD', '["python", "app.py"]');

            // 事件监听
            addConfigBtn.addEventListener('click', () => addConfig());
            downloadBtn.addEventListener('click', downloadDockerfile);
            copyBtn.addEventListener('click', copyToClipboard);
            resetBtn.addEventListener('click', resetAllConfigs);
            fileUpload.addEventListener('change', handleFileUpload);
            dragDropUpload.addEventListener('change', handleFileUpload);

            // 拖放事件
            dragDropArea.addEventListener('dragover', (e) => {
                e.preventDefault();
                dragDropArea.style.borderColor = 'var(--primary)';
                dragDropArea.style.backgroundColor = 'rgba(36, 150, 237, 0.1)';
            });

            dragDropArea.addEventListener('dragleave', () => {
                dragDropArea.style.borderColor = '#ced4da';
                dragDropArea.style.backgroundColor = '';
            });

            dragDropArea.addEventListener('drop', (e) => {
                e.preventDefault();
                dragDropArea.style.borderColor = '#ced4da';
                dragDropArea.style.backgroundColor = '';

                if (e.dataTransfer.files.length) {
                    handleDockerfileFile(e.dataTransfer.files[0]);
                }
            });

            // 初始更新预览
            updatePreview();
        }

        // 添加配置项
        function addConfig(type = 'FROM', value = '') {
            const id = 'config-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9);
            const config = { id, type, value };
            configs.push(config);
            renderConfigItem(config);
            updatePreview();
            return id;
        }

        // 渲染配置项
        function renderConfigItem(config) {
            const configItem = document.createElement('div');
            configItem.className = 'config-item';
            configItem.id = config.id;

            const typeOptions = configTypes.map(t =>
                `<option value="${t.value}" ${config.type === t.value ? 'selected' : ''}>${t.label}</option>`
            ).join('');

            const placeholder = configTypes.find(t => t.value === config.type)?.placeholder || '';

            configItem.innerHTML = `
                <div class="config-header">
                    <div class="config-type">
                        <select class="form-control config-type-select">
                            ${typeOptions}
                        </select>
                    </div>
                    <div class="config-actions">
                        <button class="btn btn-danger config-delete-btn">
                            <i class="fas fa-trash"></i>
                        </button>
                    </div>
                </div>
                <div class="config-content">
                    <div class="form-group">
                        <textarea class="form-control config-value" placeholder="${placeholder}">${config.value}</textarea>
                    </div>
                </div>
            `;

            configList.appendChild(configItem);

            // 事件监听
            const typeSelect = configItem.querySelector('.config-type-select');
            const valueTextarea = configItem.querySelector('.config-value');
            const deleteBtn = configItem.querySelector('.config-delete-btn');

            typeSelect.addEventListener('change', () => {
                config.type = typeSelect.value;
                const placeholder = configTypes.find(t => t.value === config.type)?.placeholder || '';
                valueTextarea.placeholder = placeholder;
                updatePreview();
            });

            valueTextarea.addEventListener('input', () => {
                config.value = valueTextarea.value;
                updatePreview();
            });

            deleteBtn.addEventListener('click', () => {
                removeConfig(config.id);
            });
        }

        // 移除配置项
        function removeConfig(id) {
            configs = configs.filter(c => c.id !== id);
            const configItem = document.getElementById(id);
            if (configItem) {
                configItem.remove();
            }
            updatePreview();
        }

        // 更新预览
        function updatePreview() {
            if (configs.length === 0) {
                previewContent.innerHTML = `<span class="comment"># 生成的Dockerfile将显示在这里</span>\n<span class="comment"># 请添加配置项开始生成</span>`;
                lineCount.textContent = '0 行';
                return;
            }

            let content = '';
            let lineNumber = 0;

            configs.forEach(config => {
                if (config.value.trim()) {
                    content += `<span class="keyword">${config.type}</span> ${escapeHtml(config.value)}\n`;
                    lineNumber++;
                }
            });

            // 计算行数
            lineCount.textContent = `${lineNumber} 行`;

            // 更新预览内容
            previewContent.innerHTML = content || `<span class="comment"># 没有有效的配置项</span>`;
        }

        // 下载Dockerfile
        function downloadDockerfile() {
            if (configs.length === 0) {
                showToast('没有内容可下载', 'error');
                return;
            }

            let content = '';
            configs.forEach(config => {
                if (config.value.trim()) {
                    content += `${config.type} ${config.value}\n`;
                }
            });

            if (!content) {
                showToast('没有有效的配置项', 'error');
                return;
            }

            const blob = new Blob([content], { type: 'text/plain' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = 'Dockerfile';
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            URL.revokeObjectURL(url);

            showToast('Dockerfile 下载成功');
        }

        // 复制到剪贴板
        function copyToClipboard() {
            if (configs.length === 0) {
                showToast('没有内容可复制', 'error');
                return;
            }

            let content = '';
            configs.forEach(config => {
                if (config.value.trim()) {
                    content += `${config.type} ${config.value}\n`;
                }
            });

            if (!content) {
                showToast('没有有效的配置项', 'error');
                return;
            }

            navigator.clipboard.writeText(content).then(() => {
                showToast('已复制到剪贴板');
            }).catch(err => {
                console.error('复制失败:', err);
                showToast('复制失败', 'error');
            });
        }

        // 重置所有配置
        function resetAllConfigs() {
            if (configs.length === 0) {
                return;
            }

            if (!confirm('确定要重置所有配置吗？此操作不可撤销。')) {
                return;
            }

            configs = [];
            configList.innerHTML = '';
            updatePreview();
            showToast('所有配置已重置');
        }

        // 处理文件上传
        function handleFileUpload(e) {
            const file = e.target.files[0];
            if (file) {
                handleDockerfileFile(file);
            }
            e.target.value = ''; // 重置文件输入
        }

        // 处理Dockerfile文件
        function handleDockerfileFile(file) {
            const reader = new FileReader();
            reader.onload = (e) => {
                try {
                    const content = e.target.result;
                    parseDockerfile(content);
                    showToast('Dockerfile 上传成功');
                } catch (error) {
                    console.error('解析Dockerfile失败:', error);
                    showToast('解析Dockerfile失败', 'error');
                }
            };
            reader.readAsText(file);
        }

        // 解析Dockerfile内容
        function parseDockerfile(content) {
            // 清空现有配置
            configs = [];
            configList.innerHTML = '';

            const lines = content.split('\n');

            lines.forEach(line => {
                line = line.trim();

                // 跳过空行和注释
                if (!line || line.startsWith('#')) {
                    return;
                }

                // 解析指令
                const parts = line.split(/\s+(.+)/);
                if (parts.length >= 2) {
                    const type = parts[0];
                    const value = parts[1];

                    // 检查是否是支持的指令类型
                    const supportedType = configTypes.find(t => t.value === type);
                    if (supportedType) {
                        addConfig(type, value);
                    }
                }
            });

            updatePreview();
        }

        // 显示提示消息
        function showToast(message, type = 'success') {
            toast.textContent = message;
            toast.className = 'toast';
            toast.classList.add(type === 'error' ? 'error' : 'success');
            toast.classList.add('show');

            setTimeout(() => {
                toast.classList.remove('show');
            }, 3000);
        }

        // HTML转义
        function escapeHtml(text) {
            const div = document.createElement('div');
            div.textContent = text;
            return div.innerHTML;
        }

        // 页面加载完成后初始化
        window.addEventListener('load', init);
    </script>
</body>
</html>